﻿using Microsoft.Extensions.Configuration;
using mozhi.smarterp.AuthorCenter.Tenants.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.ObjectExtending;
using Volo.Abp.TenantManagement;

namespace mozhi.smarterp.AuthorCenter.Tenants
{
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(ITenantAppService), typeof(TenantAppService), typeof(ICustomTenantAppService), typeof(CustomTenantAppService))]
    public class CustomTenantAppService : TenantAppService, ICustomTenantAppService
    {
        private readonly IConfiguration _configuration;
        public CustomTenantAppService(ITenantRepository tenantRepository, ITenantManager tenantManager, IDataSeeder dataSeeder, IDistributedEventBus distributedEventBus, IConfiguration configuration) :
            base(tenantRepository, tenantManager, dataSeeder, distributedEventBus)
        {
            _configuration = configuration;
        }

        public override async Task<TenantDto> CreateAsync(TenantCreateDto input)
        {
            var tenant = await TenantManager.CreateAsync(input.Name);
            input.MapExtraPropertiesTo(tenant);

            tenant = await TenantRepository.InsertAsync(tenant);

            await CurrentUnitOfWork.SaveChangesAsync();

            //await DistributedEventBus.PublishAsync(
            //    new TenantCreatedEto
            //    {
            //        Id = tenant.Id,
            //        Name = tenant.Name,
            //        Properties =
            //        {
            //            { "AdminEmail", input.AdminEmailAddress },
            //            { "AdminPassword", input.AdminPassword }
            //        }
            //    });

            //using (CurrentTenant.Change(tenant.Id, tenant.Name))
            //{
            //    //TODO: Handle database creation?
            //    // TODO: Seeder might be triggered via event handler.
            //    await DataSeeder.SeedAsync(
            //                    new DataSeedContext(tenant.Id)
            //                        .WithProperty("AdminEmail", input.AdminEmailAddress)
            //                        .WithProperty("AdminPassword", input.AdminPassword)
            //                    );
            //}

            return ObjectMapper.Map<Tenant, TenantDto>(tenant);
        }

        public override async Task DeleteAsync(Guid id)
        {
            await base.DeleteAsync(id);

            var tenantConnections = await GetConnectionAsync(new TenantConnectionFilter() { TenantId = id , MaxResultCount=1000 , SkipCount=0 });

            if (tenantConnections.Count > 0)
            {
                foreach(var tenantConnection in tenantConnections)
                {
                    await DeleteConnectionAsync(id, tenantConnection.Name);
                }
            }
        }

        public async Task DeleteConnectionAsync(Guid id, string name)
        {
            var tenant = await TenantRepository.GetAsync(id);

            var matchConnection = tenant.ConnectionStrings?.FirstOrDefault(x => x.Name == name);

            if (matchConnection == null)
                return;

            tenant.ConnectionStrings.Remove(matchConnection);
            await TenantRepository.UpdateAsync(tenant);
        }

        public async Task<List<TenantConnectionDto>> GetConnectionAsync(TenantConnectionFilter filter)
        {
            var tenant = await TenantRepository.GetAsync(filter.TenantId.Value);

            var result = new List<TenantConnectionDto>();

            if (tenant == null || tenant.ConnectionStrings == null)
                return result;

            foreach (var connectionString in tenant.ConnectionStrings)
            {
                var tenantConection = new TenantConnectionDto();
                tenantConection.TenantId = connectionString.TenantId;
                tenantConection.TenantName = tenant.Name;
                tenantConection.Name = connectionString.Name;
                tenantConection.Value = connectionString.Value;

                result.Add(tenantConection);
            }

            return result;
        }

        public async Task UpdateConnectionAsync(Guid id, List<TenantConnectionUpdateDto> input)
        {
            var tenant = await TenantRepository.GetAsync(id);

            if (tenant == null || input == null || input.Count == 0)
                return;

            foreach (var connectionUpdate in input)
            {
                tenant.SetConnectionString(connectionUpdate.Name, connectionUpdate.Value);
            }

            var connections = input.Where(x => x.Name.ToLower().Trim() != "default").ToList();

            foreach (var connection in connections)
            {
                await DistributedEventBus.PublishAsync(
                new TenantConnectionCreateEvent
                {
                    TenantId = tenant.Id,
                    ConnectionStringName = connection.Name,
                    ConnectionString = connection.Value
                });
            }

            await TenantRepository.UpdateAsync(tenant);
        }
    }
}
